/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * \file
 * \brief JPEG decoder interface using the libjpeg (from IJG)
 * \author Antti Maula <antti.maula@tkk.fi>
 * \author Jari Saarinen
 *
 * This is CJPEGDecoder version 1.0.
 * 
 *
 * Version 1.0 (9.7.2007)
 * - Initial implementation of the JPEGDecoder interface. Provides
 *   basic facilities to .. surprisingly enough .. Decode JPEG images.
 *
 * $Id: JPEGDecoder.hpp,v 1.12 2009-09-28 08:55:34 amaula Exp $
 *
 */
#ifndef _JPEGDECODER_HPP_
#define _JPEGDECODER_HPP_
#include <stdio.h>
extern "C"{
#include <jpeglib.h>
}
#include <setjmp.h>

/**
 * JPEG decoder interface using the libjpeg (from IJG)
 *
 * This is CJPEGDecoder version 1.0.
 * 
 *
 * Version 1.0 (9.7.2007)
 * - Initial implementation of the JPEGDecoder interface. Provides
 *   basic facilities to .. surprisingly enough .. Decode JPEG images.
 *
 */
class CJPEGDecoder 
{
  
  /**
   * Datatype for defining own datasource. 
   * (In this case; RAM datasource in 'buf')
   */
  typedef struct _jbuf_t {
    struct jpeg_source_mgr pub;
    JOCTET * buffer;
    int buflen;
  } jbuf_t;

public:

  /**
   * Default constructor. If called with parameters, the assigned
   * pointer is assigned as JPEG source. See 'SetJPEGDataPtr' for more
   * info.
   * 
   * @param[in] aData           Pointer to JPEG data to decode.
   * @param[in] aDataLen        Maximum available datasize in this buffer.
   */
  CJPEGDecoder(const char *aData = NULL, const int aDataLen = 0);


  /**
   * Default destructor.
   */
  ~CJPEGDecoder();
  

  /**
   * Assigns a pointer to read data from. NOTE: This only stores the
   * datasource pointer. Therefore, you must NOT destroy or modify the
   * provided pointer while using the instance. \See ReleaseJPEGDataPtr
   * for more info. 
   * The SetJPEGDataPtr can be called again right after the user has
   * read all the data needed. (Image sizes, RGB data etc). This means that
   * the CJPEGDecoder class is reusable, and doesn't have to be reallocated
   * every time new image is processed. (In fact its recommended to NOT
   * construct a new CJPEGDecoder object for every new image, because the 
   * internal RGB buffer
   * is preserved across calls, saving the time used for dynamic allocation)
   *
   * @param[in] aData           Pointer to JPEG data to decode.
   * @param[in] aDataLen        Maximum available datasize in this buffer.
   * @return                    true == success, false == failure. Note that
   *                            no analysis is done on the data itself
   *                            during this call.
   *
   */
  bool SetJPEGDataPtr(const char *aData, const int aDataLen);


  /**
   * If you really need to release the JPEG data pointer, but need to
   * retain the RGB data, this function is for you. This function takes
   * care of decoding the image (if not already done so) and releases
   * the JPEG data pointer after that. After call to this, it is safe
   * to modify/delete the previously assigned JPEG data pointer.
   *
   * @return                    true == success. The image was succesfully
   *                            decoded, and the RGB format data is now
   *                            available.
   *                            false == failure. Image decoding failed.
   *                            The JPEG data pointer is released as described,
   *                            but the RGB data is not available.
   */ 
  bool ReleaseJPEGDataPtr(void);


  /**
   * This function returns a pointer to beginning of RGB data. (In format
   * <red><green><blue><red><green>...) All single color components are 8 bits.
   * The pointer points to internal buffer, so modifying the returned buffer
   * is not allowed. Also, while using the data the instance must be kept
   * alive. Also, calling the SetJPEGDataPtr invalidates the pointer.
   * 
   * @return                    Pointer to RGB data or NULL on failure.
   *
   */
  const char *GetRGBDataPtr(void);


  /**
   * Works just like \see GetRGBDataPtr, except that the data is copied to
   * separate user-supplied buffer. This avoids buffer invalidation in case of
   * changing ptr.
   * 
   * @param[in] aDataPtr        Pointer to memory location to copy the RGB data.
   * @param[in] aMaxBufSize     Buffer size available. (May not be used completely,
   *                            but atleast the number of bytes returned by
   *                            GetRGBDataSize(void) is required)
   * @return                    true == success. Image Decompress was succesfull,
   *                            and the data is now stored to user supplied pointer.
   *                            false == failure. Image decompression failed, or 
   *                            user supplied buffer was too small.
   *
   */ 
  bool GetRGBDataCopy(char *aDataPtr, const int aMaxBufSize);


  /**
   * Returns the number of bytes required by RGB data. 
   * 
   * @return                    Positive number of bytes if JPEG Header was 
   *                            valid, otherwise -1 on error.
   *  
   */
  int GetRGBDataSize(void);

  
  /**
   * Returns the image width in pixels. 
   *
   * @return                    Positive number of pixels if JPEG header was
   *                            valid, otherwise -1 on error.
   */
  int GetImageWidth(void);


  /**
   * Returns the image height in pixels. 
   *
   * @return                    Positive number of pixels if JPEG header was
   *                            valid, otherwise -1 on error.
   */
  int GetImageHeight(void);

  
  /**
   * Returns the output color space
   * @return color space:
   * JCS_UNKNOWN,      Unknown or not specified
   * JCS_GRAYSCALE,     Monochrome 
   *	JCS_RGB,          Red/green/blue 
   * JCS_YCbCr,        Y/Cb/Cr (also known as YUV) 
   * JCS_CMYK,         C/M/Y/K
   *	JCS_YCCK          Y/Cb/Cr/K 
   */
  int GetColorSpace(void);
  
  
  /**
   * Returns the number of output color components 
   */
  int GetOutputColorComponents(void);
  
  
  /**
   * Returns the number of output components
   */
  int GetOutputComponents(void);
  
private:
  // Function to carry out reading the JPEG header.
  bool ReadJPEGHeader(void);
  
  // Decoded RGB data here.
  char *iRGBData;
  int iRGBDataSize;

  // JPEG Handling data
  struct jpeg_decompress_struct iJpegDec;
  jbuf_t iJpegBuffer;
  struct jpeg_error_mgr iJpegErr;
  jmp_buf iDecoderStartJumpPoint;

  // Status flags
  bool iGotHeader;
  bool iGotRGB;

  // JPEG Library required static callbacks.
  static void jpegdecoder_dsm_init_source(j_decompress_ptr cinfo);
  static boolean jpegdecoder_dsm_fill_input_buffer (j_decompress_ptr cinfo);
  static void jpegdecoder_dsm_skip_input_data (j_decompress_ptr cinfo, long num_bytes);
  static void jpegdecoder_dsm_term_source (j_decompress_ptr cinfo);
  static void jpegdecoder_error_exit (j_common_ptr cinfo);
  static void jpegdecoder_output_message (j_common_ptr cinfo);
  static void jpegdecoder_format_message (j_common_ptr cinfo, char * buffer);
  static void jpegdecoder_emit_message (j_common_ptr cinfo, int msg_level);


  // Private constructors (Copying of JPEGDecoder object denied)
  CJPEGDecoder(const CJPEGDecoder &)
    : iRGBData(NULL),
      iRGBDataSize(0),
      iJpegDec(),
      iJpegBuffer(),
      iJpegErr(),
      iDecoderStartJumpPoint(),
      iGotHeader(false),
      iGotRGB(false) {}
  CJPEGDecoder &operator =(const CJPEGDecoder &) { return *this; }
};

/*****************************************************************************\
 *
 * $Log: not supported by cvs2svn $
 * Revision 1.11  2008-08-14 11:54:40  amaula
 * Fixed bug in GetRGBDataCopy() function causing incorrect buffersize requirements.
 *
 * Revision 1.10  2008-02-19 21:35:46  jari
 * doc
 *
 * Revision 1.9  2008-01-31 10:28:47  janne
 *
 * libjpeg needs to be inside extern "C" in order to link in kubuntu gutsy.
 *
 * Revision 1.8  2008-01-13 11:28:11  jari
 * Purkaa nyt my�s grayscale pakatut kuvat oikein
 *
 * Revision 1.7  2007-07-09 07:08:17  amaula
 * All missing features added and bugs fixed - until proven otherwise :)
 *
 *
\*****************************************************************************/

#endif
